#include "Piece.h"

Piece::Piece()
	: m_bppShape(NULL)
	, m_bppTempShape(NULL)
	, m_bUpdatedShape(true)
{}

bool Piece::ParseFileForShape(char* filename)
{
	ifstream infile;
	bool bDone = false;
	string s;
	string sType;
	int offset;

	// set sType, which is used to find where the piece is in the file
	switch(m_iMeshIndex)
	{
	case MON:		sType = "MON";		break;
	case DOM:		sType = "DOM";		break;
	case TRI0:		sType = "TRI0";		break;
	case TRI1:		sType = "TRI1";		break;
	case TETR0:		sType = "TETR0";	break;
	case TETR1:		sType = "TETR1";	break;
	case TETR2:		sType = "TETR2";	break;
	case TETR3:		sType = "TETR3";	break;
	case TETR4:		sType = "TETR4";	break;
	case PENT0:		sType = "PENT0";	break;
	case PENT1:		sType = "PENT1";	break;
	case PENT2:		sType = "PENT2";	break;
	case PENT3:		sType = "PENT3";	break;
	case PENT4:		sType = "PENT4";	break;
	case PENT5:		sType = "PENT5";	break;
	case PENT6:		sType = "PENT6";	break;
	case PENT7:		sType = "PENT7";	break;
	case PENT8:		sType = "PENT8";	break;
	case PENT9:		sType = "PENT9";	break;
	case PENT10:	sType = "PENT10";	break;
	case PENT11:	sType = "PENT11";	break;
	}

	// attempt to open the file
	infile.open(filename);
	if(!infile.is_open())			// default the piece to be filled in completely if the file could not be found
		return false;
	else
	{
		while(!infile.eof() && !bDone)		// loops until the end of file is reached or the m_bppShape is defined
		{
			getline(infile, s);				// store the line in s
			if(offset = s.find(sType, 0) != string::npos)
			{
				getline(infile, s, '#');	// gets the entire string for that piece
				int pos = 0;			// the offset of the string for that piece
				for(int y = 0; y < m_iSize; y++)
				{
					for(int x = 0; x < m_iSize; x++)
					{
						// if the next char in the string is a newline char, skip it and move to the next one instead
						if(s[pos] == '\n')
							pos++;

						if(s[pos] == '*')
							m_bppShape[y][x] = true;
						else
							m_bppShape[y][x] = false;
						pos++;
					}
				}

				bDone = true;				// now that we've defined the shape, signal to end the function
			}
		}
		infile.close();
	}

	// FOR DEBUG USE ONLY
	//ofstream outfile;
	//outfile.open("validation.txt", ios::out | ios::app);
	//for(int y = 0; y < m_iSize; y++)
	//{
	//	for(int x = 0; x < m_iSize; x++)
	//	{
	//		if(m_bppShape[y][x])
	//			outfile << "*";
	//		else
	//			outfile << "-";
	//	}
	//	outfile << "\n";
	//}

	//outfile << "\n\n";
	//outfile.close();


	return true;
}

bool Piece::Init(int type, int owner, Vec3D pos)
{
	this->owner = owner;
	m_bSelected = false;
	m_bFirstPiece = false;
	m_iMeshIndex = type;
	m_iType = type;
	m_iTextureIndex = owner;

	// determines the size of m_bppShape based on how many pieces there are
	if(type < DOM)
		m_iSize = 2;
	else if(type < TRI0)
		m_iSize = 2;
	else if(type < TETR0)
		m_iSize = 4;
	else if(type < PENT0)
		m_iSize = 4;
	else
		m_iSize = 6;

	// dynamically allocate memory for the 2d shape grids
	AllocateShape(m_bppShape, m_iSize);
	AllocateShape(m_bppTempShape, m_iSize);

	m_v3Position = pos;
	m_v3InitialPos = pos;

	// parses shapes.txt to set the value for m_bppShape
	if(!ParseFileForShape("Resource/shapes.txt"))
		return false;

	return true;
}

void Piece::AllocateShape(bool** &shape, int size)
{
	shape = new bool*[m_iSize];
	for(int y = 0; y < m_iSize; y++)
		shape[y] = new bool[m_iSize];
}

void Piece::DeallocateShape(bool** &shape, int size)
{
	if(NULL != shape)
	{
		for(int y = 0; y < m_iSize; y++)
			delete [] shape[y];

		delete [] shape;
	}
}

void Piece::CreateWorldTransform(D3DXMATRIX &matWorld)
{
	D3DXMatrixScaling(&m_matScale,							// prepare the scale matrix
							m_fScale, 
							m_fScale, 
							m_fScale);

	D3DXMatrixRotationYawPitchRoll(&m_matRotation,			// prepare the rotation matrix
										(float)m_rRotation.yaw, 
										(float)m_rRotation.pitch, 
										(float)m_rRotation.roll);

	D3DXMatrixTranslation(&m_matTrans,						// prepare the translation matrix
								m_v3Position.x, 
								m_v3Position.y, 
								m_v3Position.z);

	// combine the above matrices into the world matrix
	D3DXMatrixMultiply(&matWorld, &m_matScale, &m_matRotation);
	D3DXMatrixMultiply(&matWorld, &matWorld, &m_matTrans);
}

void Piece::Rotate(int direction)
{	
	if(LEFT == direction)
	{
		// rotate left by starting y and 0 and incrementing y
		for(int y = 0; y < m_iSize; y++)
		{
			for(int x = 0; x < m_iSize; x++)
			{
				m_bppTempShape[y][x] = m_bppShape[x][y];	// reverses the x and y coordinates
			}
		}

		//m_rRotation.yaw += 90;
	}
	
	else
	{	// rotate right by starting y and m_iSize and decrementing
		for(int y = m_iSize; y < m_iSize; y--)
		{
			for(int x = 0; x < m_iSize; x++)
			{
				m_bppTempShape[y][x] = m_bppShape[x][y];	// reverses the x and y coordinates
			}
		}
		//m_rRotation.yaw -= 90;
	}
	// once the temp array is finished, copy the values to the main shape array
	for(int y = 0; y < m_iSize; y++)
		for(int x = 0; x < m_iSize; x++)
			m_bppShape[y][x] = m_bppTempShape[y][x];

	// now that it has changed, reflag it has updated
	m_bUpdatedShape = true;
}

void Piece::Move(Direction dir)
{
	if(dir.up)		m_v3Position.z += 10;
	if(dir.down)	m_v3Position.z -= 10;
	if(dir.right)	m_v3Position.x += 10;
	if(dir.left)	m_v3Position.x -= 10;	
}

void Piece::MoveTo(float xPos, float zPos)
{
	m_v3Position.x = xPos;
	m_v3Position.z = zPos;
}

Piece::Piece(Piece const & a_copy)
	: m_bppShape(NULL)
	, m_bppTempShape(NULL)
{

	m_v3Position = a_copy.m_v3Position;
	m_bSelected = a_copy.m_bSelected;
	m_bFirstPiece = a_copy.m_bFirstPiece;
	m_v3InitialPos = a_copy.m_v3InitialPos;
	owner = a_copy.owner;
	m_iSize = a_copy.m_iSize;
	AllocateShape(m_bppShape, m_iSize);

	for(int z = 0; z < m_iSize; z++)
	{
		for(int x = 0; x < m_iSize; x++)
			m_bppShape[z][x] = a_copy.m_bppShape[z][x];
	}
}

void Piece::Return()
{
	m_v3Position = m_v3InitialPos;
}

Piece::~Piece()
{
	// release memory
	DeallocateShape(m_bppShape, m_iSize);
	DeallocateShape(m_bppTempShape, m_iSize);
}